// Copyright (c) 2008 screamingtarget@gmail.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.


#pragma once

#include <boost/asio.hpp >
#include <boost/bind.hpp>
#include <string>
#include <vector>

#include "Connection.h"


const UINT RWM_SERVERSTARTED = RegisterWindowMessage( _T("RWM_SERVERSTARTED__D33F0C3A_17FC_4b34_BA4C_75D7F974CDE2") );
const UINT RWM_SERVERPROCACCEPT = RegisterWindowMessage( _T("RWM_SERVERPROCACCEPT__0764BDD2_20C7_4e42_8B79_E6F72676D9C4") );
const UINT RWM_SERVERPROCEXIT = RegisterWindowMessage( _T("RWM_SERVERPROCEXIT__2E2E27E2_6A8B_4d30_840D_6F6806698012") );


using boost::asio::ip::tcp;


typedef std::vector< std::string > StringVector;


class Server : private boost::noncopyable
{
public:

   Server( tcp::endpoint& endpoint, HWND hWnd ) : 
      io_service_(), acceptor_( io_service_, endpoint ), hwndNotify_( hWnd )
   {
      StartAccept();
   }

   void Start()
   {
      ::PostMessage( hwndNotify_, RWM_SERVERSTARTED, 0, 0 );
      io_service_.run();
   }

   void Stop()
   {
      io_service_.post( boost::bind( &Server::HandleStop, this ) );
   }

   static StringVector GetIpAddresses()
   {
      StringVector ipAddresses;

      try
      {
         boost::asio::io_service io_service;

         tcp::resolver resolver( io_service );
         tcp::resolver::query query( boost::asio::ip::host_name(), "" );
         tcp::resolver::iterator it = resolver.resolve( query );

         while ( it != tcp::resolver::iterator() )
         {
            boost::asio::ip::address addr = (it++)->endpoint().address();

            if ( addr.is_v4() )
            {
               ipAddresses.push_back( addr.to_string() );
            }
         }
      }
      catch ( std::exception& /*e*/ )
      {
         
      }

      return ipAddresses;
   }

private:

   boost::asio::io_service io_service_;
   tcp::acceptor acceptor_;

   HWND hwndNotify_;

   ConnectionPtr connection_;


   void StartAccept()
   {
      ConnectionPtr connection( new Connection( acceptor_.io_service(), hwndNotify_ ) );

      acceptor_.async_accept( connection->socket(),
         boost::bind( &Server::HandleAccept, this, connection, boost::asio::placeholders::error ) );
   }

   void HandleAccept( ConnectionPtr connection, const boost::system::error_code& error )
   {
      if ( !error )
      {
         ::PostMessage( hwndNotify_, RWM_SERVERPROCACCEPT, 0, 0 );
         connection_ = connection;
         connection_->Start();

         StartAccept();
      }
   }

   void HandleStop()
   {
      acceptor_.close();

      if ( connection_ )
      {
         connection_->Stop();
      }

      io_service_.stop();
   }
};